package com.ingenico.insider.services.impl;

import java.io.File;
import java.util.MissingResourceException;
import java.util.logging.Logger;

import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import com.ingenico.insider.swing.LayoutLoadAction;
import com.ingenico.insider.swing.LayoutLoadDefaultAction;
import com.ingenico.insider.swing.LayoutSaveAction;
import com.ingenico.insider.swing.LayoutSaveAsAction;
import com.ingenico.insider.swing.LayoutSaveDefaultAction;
import com.ingenico.insider.util.Constants;

public final class LayoutControlSupplier {
	private static final Logger _logger = Logger.getLogger(LayoutControlSupplier.class.getCanonicalName());

	/**
	 * Public constant keywords
	 */
	public static final String LAYOUT_KEY = "layout";

	public static final String LAYOUT_LOAD_PATH = LAYOUT_KEY + Constants.SEPARATOR + "load";
	public static final String LAYOUT_SAVE_PATH = LAYOUT_KEY + Constants.SEPARATOR + "save";
	public static final String LAYOUT_SAVEAS_PATH = LAYOUT_KEY + Constants.SEPARATOR + "saveas";
	public static final String DEFAULT_KEY = "default";
	public static final String LAYOUT_LOAD_DEFAULT_PATH = LAYOUT_KEY + Constants.SEPARATOR + DEFAULT_KEY + Constants.SEPARATOR + "load";
	public static final String LAYOUT_SAVE_DEFAULT_PATH = LAYOUT_KEY + Constants.SEPARATOR + DEFAULT_KEY + Constants.SEPARATOR + "save";

	public static final String DEFAULT_LAYOUT_PATH_PATH = DEFAULT_KEY + Constants.SEPARATOR + "path";
	public static final String DEFAULT_LAYOUT_FILE_PATH = DEFAULT_KEY + Constants.SEPARATOR + "file";
	public static final String IO_MESSAGE_KEY = "io";
	public static final String OVERWRITE_MESSAGE_KEY = "overwrite";

	/**
	 * singleton instance
	 */
	private static LayoutControlSupplier instance;

	/**
	 * The Layout Actions used with menu items and buttons
	 */
	private final LayoutLoadAction loadLayoutAction;
	private final LayoutLoadDefaultAction loadDefaultLayoutAction;
	private final LayoutSaveAction saveLayoutAction;
	private final LayoutSaveDefaultAction saveDefaultLayoutAction;
	private final LayoutSaveAsAction saveAsLayoutAction;

	/**
	 * The layout menu that the one and only instance of ThemesMenuSupplier manages
	 */
	private final JMenu layoutMenu;

	/**
	 * The file chooser dialog box that is used to select layout files.
	 *
	 *  Layout files therefore confined in their own path and do not mix up with
	 * curves or other components directories
	 */
	private final JFileChooser fileChooser;

	/**
	 * The default file from which the default layout is loaded and to which it is saved.
	 */
	private File defaultFile; 
	
	/**
	 * private constructor of final class to prevent external instantiation
	 */
	private LayoutControlSupplier() {
		// Create actions
		loadLayoutAction = (LayoutLoadAction) LocalisationSupplier.getInstance().localize(new LayoutLoadAction(),LAYOUT_LOAD_PATH);
		loadDefaultLayoutAction = (LayoutLoadDefaultAction) LocalisationSupplier.getInstance().localize(new LayoutLoadDefaultAction(), LAYOUT_LOAD_DEFAULT_PATH);
		saveDefaultLayoutAction = (LayoutSaveDefaultAction) LocalisationSupplier.getInstance().localize(new LayoutSaveDefaultAction(), LAYOUT_SAVE_DEFAULT_PATH);
		saveAsLayoutAction = (LayoutSaveAsAction) LocalisationSupplier.getInstance().localize(new LayoutSaveAsAction(), LAYOUT_SAVEAS_PATH);
		// save is disabled first because no file has been loaded yet
		saveLayoutAction = (LayoutSaveAction) LocalisationSupplier.getInstance().localize(new LayoutSaveAction(), LAYOUT_SAVE_PATH);
		saveLayoutAction.setEnabled(false);

		// Construct and init the file chooser
		fileChooser = new JFileChooser();
		initFileChooser();
		initDefaultFile();

		layoutMenu = getLayoutMenu();
		_logger.finer("layout menu = " + layoutMenu);

		_logger.fine("Initializing layout menu.");
		initLayoutMenu();

		_logger.fine("Registering themes menu under the display menu.");
		StandardMenuSupplier.getInstance().getWindowsMenu().add(layoutMenu);
	}

	/**
	 * retrieve the singleton instance
	 *
	 * @return the LayoutControlSupplier singleton
	 */
	public static LayoutControlSupplier getInstance() {
		if (instance == null) {
			_logger.info(LayoutControlSupplier.class.getName() + " instance does not exist... Creating instance.");
			instance = new LayoutControlSupplier();
		}
		return instance;
	}

	/**
	 * 
	 */
	private void initLayoutMenu() {
		JMenuItem menuItem;
		
		menuItem = new JMenuItem();
		menuItem.setAction(loadDefaultLayoutAction);
		layoutMenu.add(menuItem);

		menuItem = new JMenuItem();
		menuItem.setAction(saveDefaultLayoutAction);
		layoutMenu.add(menuItem);

		layoutMenu.addSeparator();
		
		menuItem = new JMenuItem();
		menuItem.setAction(loadLayoutAction);
		layoutMenu.add(menuItem);

		menuItem = new JMenuItem();
		menuItem.setAction(saveLayoutAction);
		layoutMenu.add(menuItem);

		menuItem = new JMenuItem();
		menuItem.setAction(saveAsLayoutAction);
		layoutMenu.add(menuItem);
	}

	private void initDefaultFile() {
		String resourceKey;
		String resourceString;

		// By default, these actions are not enabled until we found a valid configuration...
		loadDefaultLayoutAction.setEnabled(false);
		saveDefaultLayoutAction.setEnabled(false);

		// Setting up default path from resource bundle data
		resourceKey = Constants.INSIDER_BASE + Constants.SEPARATOR + LAYOUT_KEY + Constants.SEPARATOR + DEFAULT_LAYOUT_FILE_PATH;
		try {
			resourceString = UserPreferencesSupplier.getInstance().getString(resourceKey);
			if ( ! resourceString.isEmpty()) {
				final File defaultLayoutFile = new File(resourceString);
				if ( ( ! defaultLayoutFile.exists()) || (defaultLayoutFile.isFile()) ) {
					this.defaultFile = defaultLayoutFile;
					_logger.fine("Using \"" + resourceString +"\" as the default layout file.");

					// Enable the load/save default actions as we just found a valid configuration...
					loadDefaultLayoutAction.setEnabled(true);
					saveDefaultLayoutAction.setEnabled(true);

					// Load file if it exists
					if (defaultLayoutFile.exists()) {
						loadDefault();
					}
				} else {
					_logger.warning("Resource \"" + resourceKey + "\"=\"" + resourceString + "\" does not contain a usable file.");
				}
			} else {
				_logger.info("Resource \"" + resourceKey + "\" is empty. Cannot set default layout file.");
			}
		} catch (MissingResourceException mre) {
			_logger.info("Resource \"" + resourceKey + "\" is missing. Cannot set default layout file.");
		}
	}

	private void initFileChooser() {
		String resourceKey;
		String resourceString;

		// Setting up default path from resource bundle data
		resourceKey = Constants.INSIDER_BASE + Constants.SEPARATOR + LAYOUT_KEY + Constants.SEPARATOR + DEFAULT_LAYOUT_PATH_PATH;
		try {
			resourceString = UserPreferencesSupplier.getInstance().getString(resourceKey);
			if ( ! resourceString.isEmpty()) {
				final File defaultLayoutPath = new File(resourceString);
				if (defaultLayoutPath.isDirectory()) {
					fileChooser.setCurrentDirectory(defaultLayoutPath);
				} else {
					_logger.warning("Resource \"" + resourceKey + "\"=\"" + resourceString + "\" does not point to an actual directory. Cannot set default layout path.");
				}
			} else {
				_logger.info("Resource \"" + resourceKey + "\" is empty. Cannot set default layout path.");
			}
		} catch (MissingResourceException mre) {
			_logger.info("Resource \"" + resourceKey + "\" is missing. Cannot set default layout path.");
		}

		// Only one layout can be chosen at a time...
		fileChooser.setMultiSelectionEnabled(false);
	}

	/**
	 * Convenience method that returns the layout menu
	 * 
	 * @return the layout menu
	 */
	public JMenu getLayoutMenu () throws MissingResourceException {
		return StandardMenuSupplier.getInstance().getStandardMenu(LAYOUT_KEY);
	}

	/**
	 * Returns the LoadLayout action used with menu items and buttons
	 *
	 * @return the LoadLayout action
	 */
	public LayoutLoadAction getLoadLayoutAction() {
		return loadLayoutAction;
	}

	/**
	 * Returns the LoadDefaultLayout action used with menu items and buttons
	 *
	 * @return the LoadDefaultLayout action
	 */
	public LayoutLoadDefaultAction getLoadDefaultLayoutAction() {
		return loadDefaultLayoutAction;
	}

	/**
	 * Returns the SaveLayout action used with menu items and buttons
	 *
	 * @return the SaveLayout action
	 */
	public LayoutSaveAction getSaveLayoutAction() {
		return saveLayoutAction;
	}

	/**
	 * Returns the SaveDefaultLayout action used with menu items and buttons
	 *
	 * @return the SaveDefaultLayout action
	 */
	public LayoutSaveDefaultAction getSaveDefaultLayoutAction() {
		return saveDefaultLayoutAction;
	}

	/**
	 * Returns the SaveAsLayout action used with menu items and buttons
	 *
	 * @return the SaveAsLayout action
	 */
	public LayoutSaveAsAction getSaveAsLayoutAction() {
		return saveAsLayoutAction;
	}

	public void load() {
		final int status = fileChooser.showOpenDialog(DockableViewsSupplier.getInstance().getComponent());
		if (status == JFileChooser.APPROVE_OPTION) {
			final File selectedFile = fileChooser.getSelectedFile();
			DockableViewsSupplier.getInstance().loadLayout(selectedFile);
			saveLayoutAction.setEnabled(true);
		}
	}

	public void loadDefault() {
		if (defaultFile != null) {
			DockableViewsSupplier.getInstance().loadLayout(defaultFile);
		} else {
			_logger.severe("Cannot load default layout : defaultFile==null");
		}
	}

	public void save() {
		final File selectedFile = fileChooser.getSelectedFile(); 
		if (selectedFile != null) {
			DockableViewsSupplier.getInstance().saveLayout(selectedFile);
		} else {
			saveAs();
		}
	}

	public void saveAs() {
		boolean isInteracting = true;
		boolean fileChoosen = false;
		int status;

		do {
			// Prompt the user for a file
			status = fileChooser.showSaveDialog(DockableViewsSupplier.getInstance().getComponent());
			switch (status) {
			case JFileChooser.APPROVE_OPTION:
				final File selectedFile = fileChooser.getSelectedFile();

				if (selectedFile.exists()) {
					status = MessageBoxSupplier.getInstance().showConfirmDialog(OVERWRITE_MESSAGE_KEY, selectedFile);
					switch (status) {
					case JOptionPane.YES_OPTION:
						// The user accepts to overwrite the file
						fileChoosen = true;
						isInteracting = false;
						break;
					case JOptionPane.NO_OPTION:
						// The user do not want to overwrite the file but did not cancel
						isInteracting = true;
						break;
					default:
						isInteracting = false;
					}
				} else {
					fileChoosen = true;
					isInteracting = false;
				}
				if (fileChoosen) {
					DockableViewsSupplier.getInstance().saveLayout(selectedFile);
					saveLayoutAction.setEnabled(true);
				}
				break;
			default:
				isInteracting = false;
			}
		} while (isInteracting);
	}

	public void saveDefault() {
		DockableViewsSupplier.getInstance().saveLayout(defaultFile);
	}
}
